package inabit.data;

import inabit.base.WorkingMemory;
import inabit.data.expression.Expression;
import inabit.utils.CompareStrategy;

import java.util.ArrayList;
import java.util.List;
/**A pure form of the rule, it takes a precedent and a consequent Expression
 * of any form.
 * @author Rafael Rocha*/
public class Rule implements Comparable<Rule>{
	private String id;
	private Expression precedent;
	private Expression consequent;
	private CompareStrategy<Rule> compareStrategy;
	
	public Rule(String id, Expression precedent, Expression consequent) {
		this.id = id;
		this.precedent = precedent;
		this.consequent = consequent;
		compareStrategy = new RuleNameCompareStrategy();
	}
	/**The compare strategy is used so that the method Collections.sort can order the rules
	 * at different ways, by default the rules are ordered at alphanumeric of theirs ids*/
	public void setCompareStrategy(CompareStrategy<Rule> cs){
		this.compareStrategy = cs;
	}
	/**Returns the compare strategy implemented by this rule*/
	public CompareStrategy<Rule> getCompareStrategy() {
		return compareStrategy;
	}
	/**Returns the rule id*/
	public String getID() {
		return id;
	}
	/**Returns a tagged description of the rule body*/
	public String getBodyDescription() {
		return "<if> " + getPrecedent() + " <then> " + getConsequent();
	}
	/**Returns the precedent expression*/
	public Expression getPrecedent() {
		return precedent;
	}
	/**Returns the consequent expression*/
	public Expression getConsequent() {
		return consequent;
	}
	/**Returns a value representing the truth degree of the precedent expression,
	 * at a crisp environment this value must be 0.0 or 1.0*/
	public Double evaluate(WorkingMemory wm) {
		return precedent.evaluate(wm);
	}
	/**Returns all the variables associated with this rule, including variables at the arithmetic expression*/
	public List<Variable> getRelatedVariables(WorkingMemory wm) {
		List<Variable> relatedVariables = new ArrayList<Variable>();
		for(String varId : getRelatedVariablesIds()){
			relatedVariables.add(wm.getVariable(varId));
		}
		return relatedVariables;
	}
	/**Returns the id of the variables associated with this rule*/
	public List<String> getRelatedVariablesIds() {
		List<String> relatedVariables = new ArrayList<String>();
		relatedVariables.addAll(consequent.getReferencedVariablesIds());
		relatedVariables.addAll(precedent.getReferencedVariablesIds());
		return relatedVariables;
	}
	@Override
	public int compareTo(Rule rule) {
		return compareStrategy.compare(this, rule);
	}
}
